/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package networking;

import gui.ClientFrame;
import gui.WNSimGuideIntroFrame;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

/**
 * Manipulates communication as a client
 * @author Arvanitis Ioannis
 */
public class Client implements Runnable {

    private Socket requestSocket;
    private ObjectOutputStream out;
    private ObjectInputStream in;
    private Object obj;
    private String host;
    private int port;
    private int newPort;
    private boolean connected;
    private Thread runner;

    public Client(String host, int port) {
        this.host = host;
        this.port = port;
        try {
            //1. creating a socket to connect to the server
            requestSocket = new Socket(host, port);
            connected = true;
            print("Connected to " + host + " in port " + port);
            //2. get Input and Output streams
            out = new ObjectOutputStream(requestSocket.getOutputStream());
            out.flush();
            in = new ObjectInputStream(requestSocket.getInputStream());
        } catch (UnknownHostException uhex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, uhex);
        } catch (IOException ioex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ioex);
        }
        runner = new Thread(this);
        runner.start();
    }

    public void run() {
        try {
            //3: Communicating with the server
            while (connected) {
                try {
                    obj = in.readObject();
                    print("server>" + obj.toString());
                    if (obj instanceof SocketMessageFactory) {
                        SocketMessageFactory smf = (SocketMessageFactory) obj;
                        if (smf.getMsgType().equals("CONNECTION_INFO")) {
                            newPort = smf.getPort();
                            smf = new SocketMessageFactory();
                            smf.setMsgType("CONNECTION_CLOSE");
                            sendMessage(smf);
                            connected = false;
                        }
                    }
                } catch (ClassNotFoundException cnfex) {
                    System.err.println("data received in unknown format");
                }
            }
        } catch (UnknownHostException uhex) {
            System.err.println("You are trying to connect to an unknown host!");
        } catch (IOException ioex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ioex);
        } finally {
            //4: Closing connection
            try {
                in.close();
                out.close();
                requestSocket.close();
                if (newPort != 0) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException ex) {
                        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    new Server(newPort);
                }
            } catch (IOException ioex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ioex);
            }
        }
    }

    /**
     * Send the message
     * @param msg The message to be sent
     */
    public void sendMessage(Object msg) {
        try {
            out.writeObject(msg);
            out.flush();
            print("client>" + msg.toString());
        } catch (IOException ioex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ioex);
        }
    }

    /**
     * Prints a custom message for the server
     * @param s The string to be printed
     */
    private void print(String s) {
        Date date = new Date();
        System.out.println(" ::CLIENT:: " + date.getTime() + "\tClient\t" + s);
    }

    public static void main(String[] args) throws UnsupportedLookAndFeelException {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(WNSimGuideIntroFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            Logger.getLogger(WNSimGuideIntroFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(WNSimGuideIntroFrame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnsupportedLookAndFeelException ex) {
            Logger.getLogger(WNSimGuideIntroFrame.class.getName()).log(Level.SEVERE, null, ex);
        }
        new ClientFrame();
    }
}
